﻿using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using FarmerJoe.Helpers.Logging;
using Styx.Common;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using System;
using Styx;
using Styx.CommonBot;
using Styx.CommonBot.POI;


namespace FarmerJoe.Helpers
{
    public class CombatLogEventArgs : LuaEventArgs
    {
        public CombatLogEventArgs(string eventName, uint fireTimeStamp, object[] args) : base(eventName, fireTimeStamp, args) { }
        public double Timestamp { get { return (double)Args[0]; } }
        public string Event { get { return Args[1].ToString(); } }

        // Is this a string? bool? what? What the hell is it even used for?
        // it's a boolean, and it doesn't look like it has any real impact codewise apart from maybe to break old addons? - exemplar 4.1
        public string HideCaster { get { return Args[2].ToString(); } }

        public ulong SourceGuid { get { return ulong.Parse(Args[3].ToString().Replace("0x", string.Empty), NumberStyles.HexNumber); } }

        public WoWUnit SourceUnit { get { return ObjectManager.GetObjectsOfType<WoWUnit>(true, true).FirstOrDefault( o => o.IsValid && (o.Guid == SourceGuid || o.DescriptorGuid == SourceGuid)); } }

        public string SourceName { get { return Args[4].ToString(); } }

        public int SourceFlags { get { return (int)(double)Args[5]; } }

        public ulong DestGuid { get { return ulong.Parse(Args[7].ToString().Replace("0x", string.Empty), NumberStyles.HexNumber); } }

        public WoWUnit DestUnit { get { return ObjectManager.GetObjectsOfType<WoWUnit>(true, true).FirstOrDefault( o => o.IsValid && (o.Guid == DestGuid || o.DescriptorGuid == DestGuid)); } }

        public string DestName { get { return Args[8].ToString(); } }

        public int DestFlags { get { return (int)(double)Args[9]; } }

        public int SpellId { get { return (int)(double)Args[11]; } }

        public WoWSpell Spell { get { return WoWSpell.FromId(SpellId); } }

        public string SpellName { get { return Args[12].ToString(); } }

        public WoWSpellSchool SpellSchool { get { return (WoWSpellSchool)(int)(double)Args[13]; } }

        public object[] SuffixParams
        {
            get
            {
                var args = new List<object>();
                for (int i = 11; i < Args.Length; i++)
                {
                    if (Args[i] != null)
                    {
                        args.Add(args[i]);
                    }
                }
                return args.ToArray();
            }
        }
    }

    public static class EventHandlers
    {
        private static bool _combatLogAttached;

        public static void AttachCombatLogEvent()
        {
            if (_combatLogAttached) return;

            // DO NOT EDIT THIS UNLESS YOU KNOW WHAT YOU'RE DOING!
            // This ensures we only capture certain combat log events, not all of them.
            // This saves on performance, and possible memory leaks. (Leaks due to Lua table issues.)
            Lua.Events.AttachEvent("COMBAT_LOG_EVENT_UNFILTERED", HandleCombatLog);
            if (
                !Lua.Events.AddFilter(
                    "COMBAT_LOG_EVENT_UNFILTERED",
                    "return args[2] == 'SPELL_CAST_SUCCESS' or args[2] == 'SPELL_AURA_APPLIED' or args[2] == 'SPELL_DAMAGE' or args[2] == 'SPELL_AURA_REFRESH' or args[2] == 'SPELL_AURA_REMOVED'or args[2] == 'SPELL_MISSED' or args[2] == 'RANGE_MISSED' or args[2] =='SWING_MISSED'"))
            {
                //Log.Write(Colours.TakeNoteColour, "ERROR: Could not add combat log event filter! - Performance may be horrible, and things may not work properly!");
            }

            Log.Write(Colours.InformativeColour,LogLevel.Diagnostic, "Attached combat log");
            _combatLogAttached = true;
        }

        public static void DetachCombatLogEvent()
        {
            if (!_combatLogAttached) return;

            Log.Write(Colours.InformativeColour, LogLevel.Diagnostic, "Detached combat log");
            Lua.Events.DetachEvent("COMBAT_LOG_EVENT_UNFILTERED", HandleCombatLog);
            _combatLogAttached = false;
        }

        public static void HandleCombatLog(object sender, LuaEventArgs args)
        {
            var e = new CombatLogEventArgs(args.EventName, args.FireTimeStamp, args.Args);
            //Logger.WriteDebug("[CombatLog] " + e.Event + " - " + e.SourceName + " - " + e.SpellName);
            switch (e.Event)
            {
                case "SPELL_AURA_APPLIED":
                    if (e.SourceGuid == StyxWoW.Me.Guid)
                    {
                        if (e.DestGuid == StyxWoW.Me.CurrentTargetGuid)
                        {
                            Timers.Reset(e.SpellName);
                        }

                        //Log.Write(Colours.TakeNoteColour, "[SPELL_AURA_APPLIED] " + e.SpellName);
                        /*
                        if (e.SpellId == 1822)
                        {
                            Common.RakeMultiplier = 1;
                            //TF
                            if (StyxWoW.Me.HasAura(5217))
                                Common.RakeMultiplier = Common.RakeMultiplier * 1.15;
                            //Savage Roar
                            if (StyxWoW.Me.HasAura(127538))
                                Common.RakeMultiplier = Common.RakeMultiplier * 1.3;
                            //Doc
                            if (StyxWoW.Me.HasAura(108373))
                                Common.RakeMultiplier = Common.RakeMultiplier * 1.25;
                        }
                        if (e.SpellId == 1079)
                        {
                            Common.ExtendedRip = 0;
                            Common.RipMultiplier = 1;
                            //TF
                            if (StyxWoW.Me.HasAura(5217))
                                Common.RipMultiplier = Common.RipMultiplier * 1.15;
                            //Savage Roar
                            if (StyxWoW.Me.HasAura(127538))
                                Common.RipMultiplier = Common.RipMultiplier * 1.3;
                            //Doc
                            if (StyxWoW.Me.HasAura(108373))
                                Common.RipMultiplier = Common.RipMultiplier * 1.25;
                        }
                         */
                    }
                    break;

                case "SPELL_AURA_REFRESH":
                    if (e.SourceGuid == StyxWoW.Me.Guid)
                    {
                        /*if (e.SpellId == 1822)
                        {
                            Common.RakeMultiplier = 1;
                            //TF
                            if (StyxWoW.Me.HasAura(5217))
                                Common.RakeMultiplier = Common.RakeMultiplier * 1.15;
                            //Savage Roar
                            if (StyxWoW.Me.HasAura(127538))
                                Common.RakeMultiplier = Common.RakeMultiplier * 1.3;
                            //Doc
                            if (StyxWoW.Me.HasAura(108373))
                                Common.RakeMultiplier = Common.RakeMultiplier * 1.25;
                        }
                        if (e.SpellId == 1079)
                        {
                            Common.ExtendedRip = 0;
                            Common.RipMultiplier = 1;
                            //TF
                            if (StyxWoW.Me.HasAura(5217))
                                Common.RipMultiplier = Common.RipMultiplier * 1.15;
                            //Savage Roar
                            if (StyxWoW.Me.HasAura(127538))
                                Common.RipMultiplier = Common.RipMultiplier * 1.3;
                            //Doc
                            if (StyxWoW.Me.HasAura(108373))
                                Common.RipMultiplier = Common.RipMultiplier * 1.25;
                        }
                         */
                    }
                    break;

                case "SPELL_DAMAGE":
                    if (e.SourceGuid == StyxWoW.Me.Guid)
                    {
                       /* if (e.SpellId == 5221 || e.SpellId == 114236 || e.SpellId == 102545)
                            //Normal Shred, Glyphed Shred, Ravage
                            Common.ExtendedRip = Common.ExtendedRip + 1;
                        */
                    }
                    break;

                case "SPELL_AURA_REMOVED":
                    if (e.SourceGuid == StyxWoW.Me.Guid)
                    {
                        /*if (e.SpellId == 1822)
                        {
                            Common.RakeMultiplier = 0;
                        }
                        if (e.SpellId == 1079)
                        {
                            Common.ExtendedRip = 0;
                            Common.RipMultiplier = 0;
                        }
                         */
                    }
                    break;
                case "SPELL_CAST_SUCCESS":
                    if (e.SourceGuid != StyxWoW.Me.Guid)
                    {
                        return;
                    }
                    /*if (StyxWoW.Me.Class == WoWClass.Druid)
                        Common.prevSwift = e.SpellId == 132158;
                     */

                
                    Timers.Reset(e.SpellName);
                    //Log.Write(Colours.TakeNoteColour, "[SPELL_CAST_SUCCESS] " + e.SpellName);
                
                    // Update the last spell we cast. So certain classes can 'switch' their logic around.
                    Spells.LastSpellCast = e.SpellName;
                    

                    // Force a wait for all summoned minions. This prevents double-casting it.
                    if (StyxWoW.Me.Class == WoWClass.Warlock && e.SpellName.StartsWith("Summon "))
                    {
                        StyxWoW.SleepForLagDuration();
                    }
                    break;

                case "SWING_MISSED":
                    if (e.SourceGuid == StyxWoW.Me.Guid)
                    {
                        if (e.Args[11].ToString() == "EVADE")
                        {
                            Log.Write(Colours.TakeNoteColour, "Mob is evading swing. Blacklisting it!");
                            Blacklist.Add(e.DestGuid, TimeSpan.FromMinutes(30));
                            if (StyxWoW.Me.CurrentTargetGuid == e.DestGuid)
                            {
                                StyxWoW.Me.ClearTarget();
                            }

                            BotPoi.Clear("Blacklisting evading mob");
                            StyxWoW.SleepForLagDuration();
                        }
                        else if (e.Args[11].ToString() == "IMMUNE")
                        {
                            WoWUnit unit = e.DestUnit;
                            if (unit != null && !unit.IsPlayer)
                            {
                                Log.Write(Colours.TakeNoteColour,
                                          string.Format("{0} is immune to {1} spell school", unit.Name, e.SpellSchool));
                                SpellImmunityManager.Add(unit.Entry, e.SpellSchool);
                            }
                        }
                    }
                    break;

                case "SPELL_MISSED":
                case "RANGE_MISSED":
                    if (e.SourceGuid == StyxWoW.Me.Guid)
                    {
                        if (e.Args[14].ToString() == "EVADE")
                        {
                            Log.Write(Colours.TakeNoteColour, "Mob is evading ranged attack. Blacklisting it!");
                            Blacklist.Add(e.DestGuid, TimeSpan.FromMinutes(30));
                            if (StyxWoW.Me.CurrentTargetGuid == e.DestGuid)
                            {
                                StyxWoW.Me.ClearTarget();
                            }

                            BotPoi.Clear("Blacklisting evading mob");
                            StyxWoW.SleepForLagDuration();
                        }
                        else if (e.Args[14].ToString() == "IMMUNE")
                        {
                            WoWUnit unit = e.DestUnit;
                            if (unit != null && !unit.IsPlayer)
                            {
                                Log.Write(Colours.TakeNoteColour,
                                          string.Format("{0} is immune to {1} spell school", unit.Name, e.SpellSchool));
                                SpellImmunityManager.Add(unit.Entry, e.SpellSchool);
                            }
                        }
                        else if (e.SourceGuid == StyxWoW.Me.Guid && (e.Args[14].ToString() != "IMMUNE") && (e.Args[14].ToString() != "EVADE"))
                        {
                            Timers.Invalidate(e.SpellName);
                            WoWUnit unit = e.DestUnit;
                            Log.Write(Colours.TakeNoteColour, string.Format("[COMBAT LOG] Cast of {0} on {1} missed. Invalidating timer.", e.SpellName, unit.Name));
                        }
                    }

                    break;
            }
        }
    }
}
